package Dm

import (
	"database/sql"
	"errors"
	"fmt"
	"db2s/ETL"
	"db2s/global"
	"regexp"
	"strings"
	"time"
)

type SchemaObjectMeta struct {
}

func extractDbConnInfo(d *sql.DB) (ipPortSid string) {
	driverInfo := fmt.Sprintf("%v", d.Driver())
	// 提取相关信息
	start := strings.Index(driverInfo, "Local")
	end := strings.Index(driverInfo[start:], "}") + start
	connectionInfo := driverInfo[start:end]
	localEnd := strings.Index(connectionInfo, ":{")
	connectionInfo = strings.ReplaceAll(connectionInfo[:localEnd], "Local", "")
	// 提取 IP 和端口
	ipPortSid = strings.TrimSpace(connectionInfo)
	return
}
func useLocalDblinkExist(objectName string, s global.SchemaObjectInput) (status bool, err error) {
	var (
		f1 any
	)
	active := ETL.InstanceActiveS{DBType: "oracle", DB: s.DB["single"], SqlMode: true}
	execSql1 := fmt.Sprintf("SELECT count(*) as \"sum\" \n"+
		"FROM DBA_DB_LINKS where 1 = 1 \n"+
		"AND DB_LINK = '%v' AND HOST = '%v' \n",
		ObjectNameToUpper(strings.TrimSpace(strings.Split(objectName, "@")[1])), extractDbConnInfo(s.DB["single"]))
	if _, f1, err = active.SqlQuery(execSql1, ETL.Map); err != nil || f1 == nil {
		return
	}
	if fmt.Sprintf("%v", f1.(map[string]any)["sum"]) == "1" {
		status = true
	}
	return
}
func timeDifference(timeStr1, timeStr2 string) (res global.TimeDifferenceResultS, err error) {
	layout := "2006-01-02 15:04:05"
	// 补全时间字符串
	time1, err1 := time.Parse(layout, timeStr1)
	time2, err2 := time.Parse(layout, timeStr2)
	if err1 != nil || err2 != nil {
		fmt.Println("Error parsing time:", err1, err2)
		return
	}
	duration := time2.Sub(time1)
	res = global.TimeDifferenceResultS{
		Second: int64(duration.Seconds()),
		Minute: int64(duration.Minutes()),
		Hour:   int64(duration.Hours()),
		Day:    int64(duration.Hours() / 24),
		Week:   int64(duration.Hours() / 24 / 7),
		Month:  int64(duration.Hours() / 720),
		Year:   int64(duration.Hours() / 720 / 12),
	}
	if res.Year == 0 && res.Month == 0 && res.Day <= 7 && res.Day > 0 { //按周处理
		if getWeekToInt(time1.Weekday())+int(res.Day)-7 == getWeekToInt(time2.Weekday()) {
			res.Week = 1
		}
	}
	return
}
func procFuncExist(event, objectName string, s global.SchemaObjectInput) (status bool, err error) {
	var (
		f1 any
	)
	active := ETL.InstanceActiveS{DBType: "oracle", DB: s.DB["single"], SqlMode: true}
	execSql1 := fmt.Sprintf("SELECT count(*) as \"sum\" \n"+
		"FROM ALL_OBJECTS\n"+
		"WHERE  OWNER = '%v' AND OBJECT_TYPE in ('FUNCTION','PROCEDURE') \n "+
		"AND OBJECT_NAME = '%v'\n  "+
		"AND STATUS = 'VALID'",
		s.Schema, ObjectNameToUpper(strings.TrimSpace(objectName)))
	if _, f1, err = active.SqlQuery(execSql1, ETL.Map); err != nil || f1 == nil {
		if err != nil {
			err = errors.New(fmt.Sprintf("%v sql exec fail. Execution process:{sql:%v,shard:%v,db:%v,err:%v}", event, execSql1, "single", s.DB, err))
		}
		return
	}
	if fmt.Sprintf("%v", f1.(map[string]any)["sum"]) == "1" {
		status = true
	}
	return
}
func truncFunc(sql string) (res string, err error) {
	res = "sysdate"
	regex := `trunc\(([^,]+)(?:,\s*'([^']+)')?\)`
	// 在表达式中查找匹配项
	re := regexp.MustCompile(regex)
	matches := re.FindStringSubmatch(sql)
	// 检查是否找到匹配项
	if len(matches) > 0 {
		// 获取函数名和参数
		functionName := "trunc"
		firstParam := matches[1] // sysdate
		if strings.Contains(firstParam, "+") {
			n := strings.Index(firstParam, "+")
			firstParam = firstParam[:n]
		}
		secondParam := matches[2] // hh24
		// 打印结果
		res = fmt.Sprintf("%v(%v%v)", functionName, firstParam, func() string {
			if len(secondParam) > 0 {
				return fmt.Sprintf(",'%v'", secondParam)
			}
			return ""
		}())
	}
	return
}

//	func sqlParse(sql string) (err error) {
//		var (
//			stmt sqlparser.Statement
//		)
//		if stmt, err = sqlparser.Parse(sql); err != nil {
//			return
//		}
//		selectStmt, ok := stmt.(*sqlparser.Select)
//		if ok {
//			for _, col := range selectStmt.SelectExprs {
//				fmt.Println("Column:", col)
//			}
//			// 访问 FROM 子句
//			for _, table := range selectStmt.From {
//				fmt.Println("Table:", table)
//			}
//		}
//		_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kongTiNue bool, err error) {
//			switch node1 := node.(type) {
//			case *sqlparser.ColName:
//				fmt.Println(node1.Name.CompliantName())
//			case *sqlparser.FuncExpr:
//				fmt.Println(node1.Exprs)
//			case *sqlparser.TableName:
//			case *sqlparser.TableSpec:
//			case *sqlparser.Select:
//			case *sqlparser.AliasedTableExpr:
//				//if tableNameExpr, ok := node1.Expr.(sqlparser.TableName); ok {
//				//	if len(tableNameExpr.Name.CompliantName()) > 0 {
//				//		if len(node1.As.String()) > 0 {
//				//			if len(tableNameExpr.Qualifier.String()) > 0 {
//				//				res = append(res, fmt.Sprintf("%v.%v", tableNameExpr.Qualifier, tableNameExpr.Name.CompliantName()))
//				//			} else {
//				//				res = append(res, tableNameExpr.Name.CompliantName())
//				//			}
//				//		} else {
//				//			if len(tableNameExpr.Qualifier.String()) > 0 {
//				//				res = append(res, fmt.Sprintf("%v.%v", tableNameExpr.Qualifier, tableNameExpr.Name.CompliantName()))
//				//			} else {
//				//				res = append(res, tableNameExpr.Name.CompliantName())
//				//			}
//				//		}
//				//	}
//				//
//				//}
//			}
//			return true, nil
//		}, stmt)
//		return
//	}
//
//	func tableNameParse(sql string) (res []string, err error) {
//		var (
//			stmt sqlparser.Statement
//		)
//		if stmt, err = sqlparser.Parse(sql); err != nil {
//			return
//		}
//		_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kongTiNue bool, err error) {
//			switch node1 := node.(type) {
//			case *sqlparser.AliasedTableExpr:
//				if tableNameExpr, ok := node1.Expr.(sqlparser.TableName); ok {
//					if len(tableNameExpr.Name.CompliantName()) > 0 {
//						if len(node1.As.String()) > 0 {
//							if len(tableNameExpr.Qualifier.String()) > 0 {
//								res = append(res, fmt.Sprintf("%v.%v", tableNameExpr.Qualifier, tableNameExpr.Name.CompliantName()))
//							} else {
//								res = append(res, tableNameExpr.Name.CompliantName())
//							}
//						} else {
//							if len(tableNameExpr.Qualifier.String()) > 0 {
//								res = append(res, fmt.Sprintf("%v.%v", tableNameExpr.Qualifier, tableNameExpr.Name.CompliantName()))
//							} else {
//								res = append(res, tableNameExpr.Name.CompliantName())
//							}
//						}
//					}
//
//				}
//			}
//			return true, nil
//		}, stmt)
//		return
//	}
func dynamicSql(s global.SchemaObjectInput, p string) (res map[string]string, err error) {
	var (
		f1         any
		event, now string
	)
	res = make(map[string]string)
	active := ETL.InstanceActiveS{DBType: "oracle", DB: s.DB["single"], SqlMode: true}
	if now, err = truncFunc(strings.ToLower(p)); err != nil {
		return nil, err
	}
	intervalSql := fmt.Sprintf("SELECT %v as \"nowTime\",%v as \"interval\" from dual", now, p)
	if _, f1, err = active.SqlQuery(intervalSql, ETL.Map); err != nil || f1 == nil {
		if err != nil {
			err = errors.New(fmt.Sprintf("%v sql exec fail. Execution process:{sql:%v,shard:%v,db:%v,err:%v}", event, intervalSql, "single", s.DB, err))
		}
		return
	}
	for k, v := range f1.(map[string]any) {
		res[k] = fmt.Sprintf("%v", v)
	}
	return
}

func (or SchemaObjectMeta) Create(s global.SchemaObjectInput) (res global.SchemaObjectReturnResult, err error) {
	return
}
